/*
 * PHY_Print.c
 *
 *  Created on: Jun 7, 2024
 *      Author: Liangmiyi
 */

#include "My_INC/PHY/PHY_Print.h"
#include "My_INC/APP/uart_process.h"
#include <stdarg.h>
#include <stdio.h>

// 串口1发送缓冲区
char Uart1TxBuffer[MAX_SIZE] = {0};    // 串口1发送缓冲区（调试用）
char Uart1RxBuffer[MAX_SIZE] = {0};    // 串口1接收缓冲区（调试用）
uint8_t Uart2TxBuffer[MAX_SIZE] = {0}; // 串口2发送缓冲区（数据通信用）
uint8_t Uart2RxBuffer[MAX_SIZE] = {0}; // 串口2接收缓冲区（数据通信用）

// DMA缓冲区管理结构实例
UART_DMA_BufferTypeDef Uart1_DMA_Buffer = {0};
UART_DMA_BufferTypeDef Uart2_DMA_Buffer = {0};

// 添加发送状态标志
volatile uint8_t uart1_is_sending = 0;
volatile uint8_t uart2_is_sending = 0;

void Uart1_Init(void)
{
    // 初始化DMA缓冲区管理结构
    Uart1_DMA_Buffer.read_index = 0;
    Uart1_DMA_Buffer.write_index = 0;

    /*USART1初始化*/
    // 配置串口方向，我这里是发送和接收都要
    LL_USART_SetTransferDirection(USART1, LL_USART_DIRECTION_TX_RX);

    /*接收配置*/
    // 使能空闲中断
    LL_USART_EnableIT_IDLE(USART1);
    // 设置内存地址，也就是设置接收的数据要放哪
    LL_DMA_SetMemoryAddress(DMA2, LL_DMA_CHANNEL_1, (uint32_t)Uart1RxBuffer);
    // 设置接收最大数据长度
    LL_DMA_SetDataLength(DMA2, LL_DMA_CHANNEL_1, MAX_SIZE);
    // 设置外设地址，也就是设置串口的数据寄存器
    LL_DMA_SetPeriphAddress(DMA2, LL_DMA_CHANNEL_1, (uint32_t)&USART1->RDR);
    // 使能DMA2发送完成中断
    LL_DMA_EnableIT_TC(DMA2, LL_DMA_CHANNEL_1);
    // 使能接收的DMA2 STREAM_2
    LL_DMA_EnableChannel(DMA2, LL_DMA_CHANNEL_1); // 使能DMA通道
    // 使能DMA串口接收
    LL_USART_EnableDMAReq_RX(USART1);

    /*发送配置*/
    // 设置外设地址，因为这个是DMA串口发送，
    LL_DMA_SetPeriphAddress(DMA2, LL_DMA_CHANNEL_2, (uint32_t)&USART1->TDR);
    // 使能DMA串口发送
    LL_USART_EnableDMAReq_TX(USART1);
    // 使能DMA2发送完成中断
    LL_DMA_EnableIT_TC(DMA2, LL_DMA_CHANNEL_2);
}

void Uart2_Init(void)
{
    // 初始化DMA缓冲区管理结构
    Uart2_DMA_Buffer.read_index = 0;
    Uart2_DMA_Buffer.write_index = 0;

    /*USART2初始化*/
    // 配置串口方向，我这里是发送和接收都要
    LL_USART_SetTransferDirection(USART2, LL_USART_DIRECTION_TX_RX);

    /*接收配置*/
    // 使能空闲中断
    LL_USART_EnableIT_IDLE(USART2);
    // 设置内存地址，也就是设置接收的数据要放哪
    LL_DMA_SetMemoryAddress(DMA2, LL_DMA_CHANNEL_3, (uint32_t)Uart2RxBuffer);
    // 设置接收最大数据长度
    LL_DMA_SetDataLength(DMA2, LL_DMA_CHANNEL_3, MAX_SIZE);
    // 设置外设地址，也就是设置串口的数据寄存器
    LL_DMA_SetPeriphAddress(DMA2, LL_DMA_CHANNEL_3, (uint32_t)&USART2->RDR);
    // 使能DMA2发送完成中断
    LL_DMA_EnableIT_TC(DMA2, LL_DMA_CHANNEL_3);
    // 使能接收的DMA2 STREAM_2
    LL_DMA_EnableChannel(DMA2, LL_DMA_CHANNEL_3); // 使能DMA通道
    // 使能DMA串口接收
    LL_USART_EnableDMAReq_RX(USART2);

    /*发送配置*/
    // 设置外设地址，因为这个是DMA串口发送，
    LL_DMA_SetPeriphAddress(DMA2, LL_DMA_CHANNEL_4, (uint32_t)&USART2->TDR);
    // 使能DMA串口发送
    LL_USART_EnableDMAReq_TX(USART2);
    // 使能DMA2发送完成中断
    LL_DMA_EnableIT_TC(DMA2, LL_DMA_CHANNEL_4);
}

void UART1_DMA_Send(uint8_t *str, uint16_t size)
{
    // 禁用DMA通道
    LL_DMA_DisableChannel(DMA2, LL_DMA_CHANNEL_2);

    // 清除所有标志位
    LL_DMA_ClearFlag_TC2(DMA2);
    LL_DMA_ClearFlag_TE2(DMA2); // 新加
    LL_DMA_ClearFlag_HT2(DMA2); // 新加

    // 配置内存地址
    LL_DMA_SetMemoryAddress(DMA2, LL_DMA_CHANNEL_2, (uint32_t)str);
    // 配置数据长度
    LL_DMA_SetDataLength(DMA2, LL_DMA_CHANNEL_2, size);
    // 使能DMA STREAM
    LL_DMA_EnableChannel(DMA2, LL_DMA_CHANNEL_2);

    // 等待UART发送完成
    while (!LL_USART_IsActiveFlag_TC(USART1))
    {
        // 等待
    }
    // 清除发送完成标志
    LL_USART_ClearFlag_TC(USART1);
}

void UART2_DMA_Send(uint8_t *str, uint16_t size)
{
    // 禁用DMA通道
    LL_DMA_DisableChannel(DMA2, LL_DMA_CHANNEL_4);

    // 清除所有标志位
    LL_DMA_ClearFlag_TC4(DMA2);
    LL_DMA_ClearFlag_TE4(DMA2);
    LL_DMA_ClearFlag_HT4(DMA2);

    // 配置内存地址
    LL_DMA_SetMemoryAddress(DMA2, LL_DMA_CHANNEL_4, (uint32_t)str);
    // 配置数据长度
    LL_DMA_SetDataLength(DMA2, LL_DMA_CHANNEL_4, size);
    // 使能DMA STREAM
    LL_DMA_EnableChannel(DMA2, LL_DMA_CHANNEL_4);

    // 等待UART发送完成
    while (!LL_USART_IsActiveFlag_TC(USART2))
    {
        // 等待
    }
    // 清除发送完成标志
    LL_USART_ClearFlag_TC(USART2);
}

int Uart1_Printf(const char *fmt, ...)
{
    // 等待上一次发送完成
    while (uart1_is_sending)
    {
        // 等待
    }

    uart1_is_sending = 1;

    va_list arg;
    va_start(arg, fmt);
    int cnt = vsprintf(Uart1TxBuffer, fmt, arg);
    va_end(arg);

    UART1_DMA_Send((uint8_t *)Uart1TxBuffer, cnt);
    uart1_is_sending = 0;

    return cnt;
}

int Uart2_Printf(const char *fmt, ...)
{
    // 等待上一次发送完成
    while (uart2_is_sending)
    {
        // 等待
    }

    uart2_is_sending = 1;

    va_list arg;
    va_start(arg, fmt);
    int cnt = vsprintf((char *)Uart2TxBuffer, fmt, arg);
    va_end(arg);

    UART2_DMA_Send(Uart2TxBuffer, cnt);
    uart2_is_sending = 0;

    return cnt;
}

// 获取DMA缓冲区中可读数据的大小
uint16_t UART_GetRxDataSize(const UART_DMA_BufferTypeDef *dma_buffer)
{
    uint16_t write_index = dma_buffer->write_index;
    uint16_t read_index = dma_buffer->read_index;

    // 特殊处理初始状态
    if (write_index == MAX_SIZE && read_index == 0)
    {
        return 0; // 初始状态，没有数据
    }

    if (write_index >= read_index)
    {
        return write_index - read_index;
    }
    else
    {
        return MAX_SIZE - read_index + write_index;
    }
}

// 从环形缓冲区读取数据
uint16_t UART_ReadData(UART_DMA_BufferTypeDef *dma_buffer, uint8_t *buffer, uint16_t max_size)
{
    // 特殊处理初始状态
    if (dma_buffer->write_index == MAX_SIZE && dma_buffer->read_index == 0)
    {
        return 0; // 初始状态，没有数据可读
    }

    uint16_t data_size = UART_GetRxDataSize(dma_buffer);
    if (data_size == 0)
    {
        return 0; // 没有数据可读
    }

    // 限制读取大小
    if (data_size > max_size)
    {
        data_size = max_size;
    }

    uint16_t read_index = dma_buffer->read_index;

    // 选择正确的接收缓冲区
    const uint8_t *rx_buffer = (dma_buffer == &Uart1_DMA_Buffer) ? (uint8_t *)Uart1RxBuffer : (uint8_t *)Uart2RxBuffer;

    // 读取数据
    if (read_index + data_size <= MAX_SIZE)
    {
        // 数据连续，一次读取
        memcpy(buffer, &rx_buffer[read_index], data_size);
    }
    else
    {
        // 数据跨越缓冲区尾部，需要分两次读取
        uint16_t first_part = MAX_SIZE - read_index;
        memcpy(buffer, &rx_buffer[read_index], first_part);
        memcpy(buffer + first_part, &rx_buffer[0], data_size - first_part);
    }

    // 更新读指针
    dma_buffer->read_index = (read_index + data_size) % MAX_SIZE;

    return data_size;
}
